/*
 * Copyright (c) 2020 - present, Inspur Genersoft Co., Ltd.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *       http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package io.iec.edp.caf.commons.transaction;

import io.iec.edp.caf.commons.utils.SpringBeanUtils;
import io.iec.edp.caf.data.source.ConnectionProvider;
import io.iec.edp.caf.data.source.DataSourceIdentifierResolver;
import lombok.extern.slf4j.Slf4j;
import org.springframework.jdbc.datasource.DataSourceUtils;
import org.springframework.transaction.*;
import org.springframework.transaction.support.DefaultTransactionDefinition;
import org.springframework.transaction.support.TransactionSynchronizationManager;

import javax.sql.DataSource;
import java.sql.Connection;

/**
 * 数据库事务对象
 * @author wangyandong
 */
@Slf4j
public class JpaTransaction {

    private TransactionStatus status = null;
    PlatformTransactionManager transactionManager = null;

    /**

     */
    public static JpaTransaction getTransaction(){
        return new JpaTransaction();
    }

    /**
     * 私有构造函数
     */
    private JpaTransaction(){

    }

    /**
     * 开启事务
     * @throws TransactionException
     */
    public void begin() {
        if (this.hasTransaction()) {
            throw new CannotCreateTransactionException("已启动事务环境！");
        }
        // 容器中获取事务管理组件
        this.transactionManager =
                (PlatformTransactionManager) SpringBeanUtils.getBean(PlatformTransactionManager.class);
        // 开始事务
        DefaultTransactionDefinition transactionDefinition = new DefaultTransactionDefinition();
        transactionDefinition.setPropagationBehavior(0);
        this.status = transactionManager.getTransaction(transactionDefinition);
    }

    /**
     * 开启事务
     * @param propagation 事务传播方式
     */
    public void begin(TransactionPropagation propagation) {
        if (this.hasTransaction()) {
            throw new CannotCreateTransactionException("已启动事务环境！");
        }
        // 容器中获取事务管理组件
        this.transactionManager =
                (PlatformTransactionManager) SpringBeanUtils.getBean(PlatformTransactionManager.class);
        // 开始事务
        DefaultTransactionDefinition transactionDefinition = new DefaultTransactionDefinition();
        transactionDefinition.setPropagationBehavior(propagation.ordinal());
        this.status = transactionManager.getTransaction(transactionDefinition);
    }

    /**
     * 开启事务
     * @param propagation 事务传播方式
     * @param timeout 超时时间（以秒为单位）
     */
    public void begin(TransactionPropagation propagation, int timeout) {
        if (this.hasTransaction()) {
            throw new CannotCreateTransactionException("已启动事务环境！");
        }
        // 容器中获取事务管理组件
        this.transactionManager =
                (PlatformTransactionManager) SpringBeanUtils.getBean(PlatformTransactionManager.class);
        // 开始事务
        DefaultTransactionDefinition transactionDefinition = new DefaultTransactionDefinition();
        transactionDefinition.setPropagationBehavior(propagation.ordinal());
        transactionDefinition.setTimeout(timeout);
        this.status = transactionManager.getTransaction(transactionDefinition);
    }


    public void commit(){
        if(hasTransaction()){
            this.transactionManager.commit(this.status);
            this.transactionManager = null;
            this.status = null;
        }
    }


    public void rollback(){
        if(hasTransaction()){
            this.transactionManager.rollback(this.status);
            this.transactionManager = null;
            this.status = null;
        }
    }

    /**
     * 获取当前事务环境下所持有的连接
     * @return connection
     */
    public Connection getConnectionFromTransaction(){
        if(log.isDebugEnabled()){
            Exception e = new Exception("This is a Log stack but not a exception");
            log.debug("FULL STACK",e);
        }
        Connection con = null;
        //判断是否在事务环境
        boolean isInTran = TransactionSynchronizationManager.isActualTransactionActive();
        if(!isInTran){
            log.info("Get null From Transaction, because transaction is not begin!");
            return null;
            //throw new RuntimeException("Transaction is not begin!");
        }else {
            //获取当前数据源
            String identifier = SpringBeanUtils.getBean(DataSourceIdentifierResolver.class).resolveDataSourceIdentifier();
            DataSource ds = SpringBeanUtils.getBean(ConnectionProvider.class).getDataSource(identifier);
            //判断是否是当前数据源构建的事务
            if(TransactionSynchronizationManager.getResource(ds)!=null){
                con = DataSourceUtils.getConnection(ds);
            }
            //con = DataSourceUtils.getConnection(ds);
        }
        if(con==null) log.error("Transaction is not begin!");
        return con;
    }

    /**
     * 判断是否在事务内
     * @return
     */
    public boolean isInTransaction(){
        boolean isInTran = TransactionSynchronizationManager.isActualTransactionActive();
        return isInTran;
    }

    /**
     * 判断当前事务是否已经开启
     * @return
     */
    private boolean hasTransaction(){
        return this.transactionManager!=null && this.status !=null&&!this.status.isCompleted();
    }
}
